package solveur;

import ilog.concert.IloNumExpr;
import ilog.concert.IloNumVar;
import ilog.concert.IloNumVarType;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;

import lpsolve.*;
import programme.Contrainte;
import programme.Programme;
import programme.Solution;
import programme.SousExpression;
import programme.TypeContrainte;
import programme.TypeVariable;
import programme.Variable;
import programme.VecteurVariables;

public class LPSOLVEInterface implements SolverInterface {

	public Solution resoudre(Programme p) throws Exception {
		Solution solution;
		try {
			LpSolve lp;
			int j, nbCol, nbLigne;

			/*nbCol est le nombre de variables*/
			nbCol = p.getNbVars();
System.out.println("nbCol : "+nbCol);
			
			/*nbLigne est le nombre de contraintes*/
			nbLigne = p.getContraintes().size()+p.getNbVars();
System.out.println("nbLigne : "+nbLigne);
			
			int[] colNo = new int[nbCol];
			double[] ligne = new double[nbLigne];
			
			/*creation du modele*/
			lp = LpSolve.makeLp(0, nbCol);
			
			if(lp.getLp() == 0) throw new LpSolveException(); /*on a pas pu creer de modele*/
		
			/*creation des variables*/
			p.nommerVariables();
			
			HashMap<Variable, Integer> variables = new HashMap<Variable, Integer>();
			
			for (int i=0 ; i<p.getNbVars() ; i++) {			
				variables.put(p.getVar(i), i);
				
				if( p.getVar(i).getType() == TypeVariable.CONTINUE){
					//rien, c'est le cas par defaut
				}
				if( p.getVar(i).getType() == TypeVariable.DISCRET){
					lp.setInt(i, true);
				}
				if( p.getVar(i).getType() == TypeVariable.BOOLEEN){
					lp.setBinary(i, true);
				}
			}
			lp.setAddRowmode(true);  /* le modele est construit ligne par ligne */

			// Toutes les variables doivent etre positives
			variables = new HashMap<Variable, Integer>();
			for (Variable var : p.getVariables()) {
				colNo[0] = var.getNumAbsolue(); /* numero de la variable */
				ligne[0] = 1; /*son coeff*/
				lp.addConstraintex(1, ligne, colNo, LpSolve.GE, 0);
			}
			
			
			/*creation des contraintes*/
			int type;
			for (Contrainte c : p.getContraintes()) {
				if (c.getType() == TypeContrainte.INF){
					type = LpSolve.LE;
				}else{
					if (c.getType() == TypeContrainte.SUP){
						type = LpSolve.GE;
					}else{
						type = LpSolve.EQ;
					}
				}
				j = 0;
				for (SousExpression ssexpr : c.getExpression().getSsExpressions()) {
					colNo[j] = ssexpr.getVar().get(0).getNumAbsolue(); /* numero de la variable */
					ligne[j++] = ssexpr.getCoef(); /*son coeff*/
				}
				
				lp.addConstraintex(j, ligne, colNo, type, c.getBorne());
			}
			
			lp.setAddRowmode(false); /* fin du modele contraint*/
			
			 /*creation de la fonction objectif*/	
			j=0;
			for (SousExpression ssexpr : p.getObjectif().getFonction().getSsExpressions()) {				
				colNo[j] = ssexpr.getVar().get(0).getNumAbsolue();
	            ligne[j++] = ssexpr.getCoef();
			}
		
			lp.setObjFnex(j, ligne, colNo);
			
			/*on definit si c'est un min ou un max*/
			if (p.getObjectif().isMin()){
				lp.setMinim();
			}else{
				lp.setMaxim();
			}
				
            /* Les messages qui seront affiches : le moins possible */
            lp.setVerbose(LpSolve.IMPORTANT);

            /* on calcule */
            lp.solve();
            
            /* on recupere les solutions */
            HashMap<Variable, Double> resultats = new HashMap<Variable, Double>();
            lp.getVariables(ligne);
         
          /*  for (Variable var : variables.keySet()) {
				resultats.put(var, (Double)ligne[j]);
			}*/
			for (int q = 0; q<nbCol; q++){
				resultats.put(p.getVar(q),(Double)ligne[q]);
				System.out.println(q +" : " + ligne[q]);
			}
         
            /*on cree la solution*/
            solution = new Solution(new ArrayList<Variable>(resultats.keySet()));
            solution.setResultat(lp.getObjective());
            solution.setValeurs(resultats);
            
            /*on libere la memoire*/
            lp.deleteLp();
            
			return solution;
			
		}catch (LpSolveException e) {
			e.printStackTrace();
			return null;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		
	}

}
